#pragma once

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
#include <unistd.h>

namespace protocol_ns
{
    const std::string SEP = "\r\n";

    // tcp中，我们读到的报文，可能是半个，可能是1个，也可能是2个...所以要解决tcp的粘报问题
    //"len\r\n{         }\r\n"
    std::string Encode(const std::string &json_str)
    {
        int json_str_len = json_str.size();
        std::string proto_str = std::to_string(json_str_len); // len
        proto_str += SEP;                                     // len\r\n
        proto_str += json_str;                                // len\r\n{    }
        proto_str += SEP;                                     // len\r\n{   }\r\n

        return proto_str;
    }

    // "len"\r\n"{
    // "len"\r\n"{             }"
    // "len"\r\n"{             }"\r\n;
    // "len"\r\n"{             }"\r\n"len";
    // "len"\r\n"{             }"\r\n"len"\r\n"{             }";
    // "len"\r\n"{             }"\r\n"len"\r\n"{             }"\r\n
    std::string Decode(std::string &inbuffer)
    {
        auto pos = inbuffer.find(SEP);

        // 没有\r\n 返回空串
        if (pos == std::string::npos)
        {
            return std::string();
        }

        // 没有长度信息，返回空串
        std::string len_str = inbuffer.substr(0, pos);
        if (len_str.empty())
        {
            return std::string();
        }
        // 获得报文长度
        int packlen = std::stoi(len_str);
        int total = packlen + SEP.size() * 2 + len_str.size(); // packlen是报文长度，sep是分隔符长度，len_str是长度信息的长度
        // 输入缓冲区里的数据长度小于正确的总长度
        if (inbuffer.size() < total)
        {
            return std::string();
        }

        // 报文是完整的
        std::string package = inbuffer.substr(pos + SEP.size(), packlen);
        inbuffer.erase(0, total);

        return package;
    }

    // 发送请求
    class Request
    {
    public:
        Request()
        {
        }
        Request(int x, int y, char oper)
            : _x(x), _y(y), _oper(oper)
        {
        }

        // 把request对象的成员数据序列化成一个json字符串
        bool Serialize(std::string *out)
        {
            // 创建一个Json::Value对象
            Json::Value root;
            // 把成员变量_x存储到Json::Value对象中，键名为x
            root["x"] = _x;
            root["y"] = _y;
            root["oper"] = _oper;

            // 创建一个Json::FastWriter对象，用于将Json::Value对象转换成json字符串
            Json::FastWriter writer;
            *out = writer.write(root);

            return true;
        }

        // 把一个json字符串反序列化
        bool Deserialize(const std::string &in)
        {
            // 用于存储解析后的json数据
            Json::Value root;
            // 用于解析json字符串
            Json::Reader reader;
            // parse方法用于：尝试将输入的字符串解析为json数据，成功则返回true
            bool res = reader.parse(in, root);
            if (!res)
            {
                return false;
            }

            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();

            return true;
        }

    //private:
        int _x;
        int _y;
        char _oper;
    };

    // 接收回复
    class Response
    {
    public:
        Response()
        {
        }

        Response(int result, int code)
            : _result(result), _code(code)
        {
        }

        bool Serialize(std::string *out)
        {
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;

            Json::FastWriter writer;
            *out = writer.write(root);
            return true;
        }

        bool Deserialize(const std::string &in)
        {
            Json::Value root;
            Json::Reader reader;
            bool res = reader.parse(in, root);
            if (!res)
            {
                return false;
            }

            _result = root["result"].asInt();
            _code = root["code"].asInt();
            return true;
        }

    // private:
        int _result;
        int _code;
    };

    // 用于创建Request 和 Response 对象
    class Factory
    {
    public:
        Factory()
        {
            srand(time(nullptr) ^ getpid());
            opers = "+/*/%^&|";
        }

        // 建立请求函数，并返回建立的request对象的指针
        std::shared_ptr<Request> BuildRequest()
        {
            int x = rand() % 10 + 1;
            usleep(x * 10);
            int y = rand() % 5;
            usleep(y * x * 5);
            char oper = opers[rand() % opers.size()];
            std::shared_ptr<Request> req = std::make_shared<Request>(x, y, oper);

            return req;
        }

        std::shared_ptr<Response> BuildResponse()
        {
            return std::make_shared<Response>();
        }

        ~Factory()
        {
        }

    private:
        // 其值为"+/*/%^&|"，在创建request对象时，会从这个字符串里随机选取一个作为操作符
        std::string opers;
    };

}